package com.dc.commons.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.List;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.dc.commons.helper.DateHelper;
import com.dc.commons.utils.excel.BodyStyle;
import com.dc.commons.utils.excel.CellData;
import com.dc.commons.utils.excel.ExcelData;
import com.dc.commons.utils.excel.ExcelStyleEnum;
import com.dc.commons.utils.excel.PipeLine;
import com.dc.commons.utils.excel.RowData;
import com.dc.commons.utils.excel.TitleStyle;

/*******************************************************************************<P>
 * 文件名: Excel.java <br>
 * 版本: 1.0<br>
 * 描述:Excel 工具类，提供导入，导出<br>
 * 版权所有: <br>
 * <P>
 * 创建者: 王建栋 <br>
 * 创建日期: 2016年6月1日 下午3:51:59<br>
 * 修改者: <br>
 * 修改日期: <br>
 * 修改说明: <br>
 ******************************************************************************/
public class Excel {

	private static Logger logger=LoggerFactory.getLogger(Excel.class);
	

	
	/*******************************************************************************
	 * 文件名: Excel.Exportor <br>
	 * 版本: 1.0<br>
	 * 描述: Excel 导出类<br>
	 * 版权所有: <br>
	 * <P>
	 * 创建者: 王建栋 <br>
	 * 创建日期: 2016年6月2日 上午11:15:18<br>
	 * 修改者: <br>
	 * 修改日期: <br>
	 * 修改说明: <br>
	 *****************************************************************************
	 */
	public static class Exportor{
		
		/**
		 * *****************************************************************************<P>
		 * 文件名: Excel.Exportor.ExcelType.java <br>
		 * 版本: 1.0<br>
		 * 描述:Excel 类型<br>
		 * 版权所有: <br>
		 * <P>
		 * 创建者: 王建栋 <br>
		 * 创建日期: 2016年6月7日 下午4:42:33<br>
		 * 修改者: <br>
		 * 修改日期: <br>
		 * 修改说明: <br>
		 *****************************************************************************
		 */
		public static enum ExcelType{
			XLS(){

				@Override
				Workbook newWorkbook() {
					return new HSSFWorkbook();
				}
				
			},XLSX{
				@Override
				Workbook newWorkbook() {
					return new XSSFWorkbook();
				}
			};
			
			/**
			 * 创建 Workbook
			 * @return Workbook
			 */
			abstract Workbook newWorkbook();
			
			void createInfomation(Workbook workbook){
			}
			
			public static ExcelType getExcelType(File file){
				String fileName=file.getName();
				String ext=fileName.substring(fileName.lastIndexOf(".")+1);
				return ExcelType.valueOf(ext.toUpperCase());
			}
		}
		
		/**
		 * 将内容循环写入到文件中
		 * @param titles 	标题列表
		 * @param pipeLine  导入管道
		 * @param file		写入的文件
		 */
		public static void export(List<String> titles,PipeLine pipeLine,File file){
			if(!file.getParentFile().exists()){
				file.getParentFile().mkdirs();
			}
			FileOutputStream out=null;
			try {
				out = new FileOutputStream(file);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
				throw new RuntimeException(e);
			}
			
			export(titles, pipeLine, ExcelStyleEnum.Default, ExcelStyleEnum.Default, out,ExcelType.getExcelType(file));
		}
		/**
		 * 将内容循环写入到文件中
		 * @param titles 	标题列表
		 * @param pipeLine  导入管道
		 * @param out		输出流
		 * @param excelType 
		 */
		public static void export(List<String> titles,PipeLine pipeLine,OutputStream out,ExcelType excelType){
			export(titles, pipeLine, ExcelStyleEnum.Default, ExcelStyleEnum.Default, out,excelType);
		}
		
		
		/**
		 * 将内容循环写入到文件中
		 * @param titles 	   标题列表
		 * @param pipeLine 	   导入管道
		 * @param out		   输出流
		 * @param titleStyle 标题样式
		 * @param bodyStyle	   正文样式
		 */
		public static void export(List<String> titles,PipeLine pipeLine,TitleStyle titleStyle,BodyStyle bodyStyle,OutputStream out,ExcelType excleType){
			
			Workbook book =excleType.newWorkbook();
			CellStyle titleCellStyle=titleStyle.titleCellStyle(book);
			CellStyle bodyCellStyle=bodyStyle.bodyCellStyle(book);
			List<List<Object>> list=null;
			while((list=pipeLine.findList())!=null&&list.size()>0){
				Sheet sheet= Helper.createSheet(book, titles, titleCellStyle);
				Helper.writeWorkBook(book, sheet, list, titles, titleCellStyle, bodyCellStyle);
			}
			// 没有数据的时候创建一个空的表头
			if(book.getNumberOfSheets()==0){
				Helper.createSheet(book, titles, titleCellStyle);
			}
			 try {
				book.write(out);
				out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		
		/**
		 * 将内容循环写入到压缩文件中
		 * @param titles 	  标题列表
		 * @param pipeLine 	  导入管道
		 * @param folder	 导出文件基本路径
		 * @param name		导出文件基本名称
		 */
		public static File exportZip(List<String> titles,PipeLine pipeLine,String folder,String name){
			return exportZip(titles, pipeLine, ExcelStyleEnum.Default, ExcelStyleEnum.Default, folder, name);
		}
		
		/**
		 * 将内容循环写入到压缩文件中
		 * @param titles 	  标题列表
		 * @param pipeLine 	  导入管道
		 * @param folder	 导出文件基本路径
		 * @param name		导出文件基本名称
		 * @param titleStyle 标题样式
		 * @param bodyStyle	   正文样式
		 */
		public static File exportZip(List<String> titles,PipeLine pipeLine,TitleStyle titleStyle,BodyStyle bodyStyle,String folder,String name){

			File folderFile=new File(folder);
			if(folderFile.exists()&&folderFile.list().length>0){
				throw new RuntimeException("文件已存在");
			}
			folderFile.mkdirs();
			List<List<Object>> list=null;
			int fileCount=0;
			
			//一次查询一个Excel，多个Excel压缩为一个文件
			while((list=pipeLine.findList())!=null&&list.size()>0){
				String fileName=name+"("+(++fileCount)+").xls";
				FileOutputStream out=null;
				HSSFWorkbook book=null;
				try{
					out=new FileOutputStream(new File(folderFile, fileName));
					book=new HSSFWorkbook();
					CellStyle titleCellStyle=titleStyle.titleCellStyle(book);
					CellStyle bodyCellStyle=bodyStyle.bodyCellStyle(book);
					Sheet sheet= Helper.createSheet(book, titles, titleCellStyle);
					
					Helper.writeWorkBook(book, sheet, list, titles, titleCellStyle, bodyCellStyle);
				}catch(Exception e){
					e.printStackTrace();
				}finally{
					try {
						book.write(out);
						book.close();
						
					} catch (IOException e) {
						e.printStackTrace();
					}
					if(out!=null){
						try {
							out.close();
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				}
			}
			
			String zipFile=folderFile.getAbsolutePath();
			try {
				ZipUtil.zip(zipFile,folderFile.getParentFile().getAbsolutePath(),folderFile.getName()+".zip");
				
			} catch (Exception e) {
				e.printStackTrace();
			}
			
			for(File file:folderFile.listFiles()){
				file.delete();
			}
			folderFile.delete();
			return folderFile;
		}
		
		
		
		
		/*******************************************************************************
		 * 文件名: Helper <br>
		 * 版本: 1.0<br>
		 * 描述: 内部辅助类<br>
		 * 版权所有: <br>
		 * <P>
		 * 创建者: 王建栋 <br>
		 * 创建日期: 2016年6月2日 上午11:20:38<br>
		 * 修改者: <br>
		 * 修改日期: <br>
		 * 修改说明: <br>
		 *****************************************************************************
		 */
		static class Helper{
			/**
			 * 创建新的Sheet页，并 初始化表头
			 * @param book
			 * @param titles
			 * @param titleStyle
			 * @param bodyStyle
			 * @return
			 */
			private static Sheet createSheet(Workbook book,List<String> titles,CellStyle titleStyle){
				Sheet sheet=book.createSheet();
				Row titleRow=sheet.createRow(0);
				for(int i=0;i<titles.size();i++){
					titleRow.createCell(i).setCellValue(titles.get(i));
					titleRow.getCell(i).setCellStyle(titleStyle);
				}
				return sheet;
			}
			
			/**
			 * 将一批数据写入到book中，如果数据超过65536 创建新的Sheet页
			 * @param book
			 * @param sheet
			 * @param list
			 * @param titles
			 * @param pipeLine
			 * @param out
			 * @param titleStyle
			 * @param bodyStyle
			 */
			public static void writeWorkBook(Workbook book,Sheet sheet,List<List<Object>> list,List<String> titles,CellStyle titleStyle,CellStyle bodyStyle){
				int count=1;
				int max=65536;
				for(List<Object> record:list){
						Row hssfRow=null;
						if(count==max){
							count=1;
							 sheet= Helper.createSheet(book, titles, titleStyle);
						}
						 hssfRow=sheet.createRow(count++);
						for(int i=0;i<record.size();i++){
							Object o=record.get(i);
							if(o instanceof Number){
								Number num=(Number)o;
								hssfRow.createCell(i).setCellValue(num.doubleValue());
								hssfRow.getCell(i).setCellType(HSSFCell.CELL_TYPE_NUMERIC);
								hssfRow.getCell(i).setCellStyle(bodyStyle);
							}else if(o instanceof Date){
								Date date=(Date)o;
								String value=DateHelper.formatDateTime(date);
								if(value.endsWith("00:00:00")){
									value=value.substring(0, 10);
								}
								hssfRow.createCell(i).setCellValue(value);
								hssfRow.getCell(i).setCellType(HSSFCell.CELL_TYPE_STRING);
								hssfRow.getCell(i).setCellStyle(bodyStyle);
							}else{
								hssfRow.createCell(i).setCellValue(o==null?"":o.toString());
								hssfRow.getCell(i).setCellType(HSSFCell.CELL_TYPE_STRING);
								hssfRow.getCell(i).setCellStyle(bodyStyle);
							}
						}
						
					}
				 
			}
		}
	}
	
	/*******************************************************************************
	 * 文件名: Excel.ImPortor.java <br>
	 * 版本: 1.0<br>
	 * 描述: Excel 导入类 支持 xls，xlxs<br>
	 * 版权所有: <br>
	 * <P>
	 * 创建者: 王建栋 <br>
	 * 创建日期: 2016年6月1日 下午4:21:16<br>
	 * 修改者: <br>
	 * 修改日期: <br>
	 * 修改说明: <br>
	 *****************************************************************************
	 */
	public static class ImPortor{
		
		
		/**
		 * 将Excel 文件的数据转换为ExcelData对象 
		 * @param file	导入文件
		 * @return ExcelData
		 */
		public static ExcelData importData(File file){
			return importData(file, 0, true);
		}
		
		
		/**
		 * 将Excel 文件的数据转换为ExcelData对象 
		 * @param file			导入文件
		 * @param sheetIndex	导入sheet索引
		 * @param hasTitle		是否包含标题
		 * @return ExcelData
		 */
		public static ExcelData importData(File file,int sheetIndex,boolean hasTitle){
			ExcelData data=new ExcelData();
			Workbook workbook=null;
			Sheet sheet = null;
			
			if(!file.exists()){
				logger.error(file+" 不存在!");
				return null;
			}
			
			try{
			
				// 根据 结尾选择不同的处理类
				if(file.getName().toLowerCase().endsWith("xls")){
					POIFSFileSystem fs=new POIFSFileSystem(new FileInputStream(file));
					workbook=new HSSFWorkbook(fs);
					sheet=workbook.getSheetAt(sheetIndex);
				}else if(file.getName().toLowerCase().endsWith("xlsx")){
					 workbook=new XSSFWorkbook(new FileInputStream(file));
					 sheet=workbook.getSheetAt(sheetIndex);
				}
				
				
				int rowNum=sheet.getLastRowNum();
				int cellNum=sheet.getRow(0).getPhysicalNumberOfCells();
				// 有标题 start 从 1开始，否则从0开始
				int start=hasTitle?1:0;
				
				//没有数据
				if(rowNum<1){
					return null;
				}
				
				//是否需要读取title
				if(hasTitle){
					for(int i=0;i<cellNum;i++){
						data.getTitle().getCells().add(CellData.valueOf(sheet.getRow(0).getCell(i)));
					}
				}
				
				for(int i=start;i<rowNum+1;i++){
					RowData row=new RowData();
					for(int j=0;j<cellNum;j++){
						row.getCells().add(CellData.valueOf(sheet.getRow(i).getCell(j)));
					}
					data.getRows().add(row);
				}
			
			}catch(Exception e){
				e.printStackTrace();
			}finally{
				try {
					workbook.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
			return data;
			
		}
	};
}
